package com.doodle.common.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.ParcelFileDescriptor;
import android.support.v4.util.LruCache;

import com.doodle.common.drawable.MeasuredAsyncDrawable;

import java.io.Closeable;

public class BitmapDrawableJob implements ThreadPool.Job<Drawable> {

	private static final String TAG = "BitmapDrawableJob";

	private final Context mContext;
	protected String mUrl;
	
	private final int mWidth;
	private final int mHeight;
	
	private final int mFitMode;
	private final int mType;
	
	private static final int STATE_INIT = 0;
    private static final int STATE_DOWNLOADING = 1;
    private static final int STATE_DOWNLOADED = 2;
    private static final int STATE_ERROR = -1;
    
	private int mState = STATE_INIT;
	
	private ParcelFileDescriptor mFileDescriptor;
	
	private static LruCache<String, Bitmap> mIconLruCache =
			new LruCache<String, Bitmap>(64);
	
	private String mDownloadFilePath = null;
	private int mRoundCornerRadius = -1;
	
	public BitmapDrawableJob(Context context, String url, int width, int height, int fitMode, int type, String downloadFilePath, int roundCornerRadius) {
		mContext = context;
		mUrl = url;
		mWidth = width;
		mHeight = height;
		mFitMode = fitMode;
		mType = type;
		mDownloadFilePath = downloadFilePath;
		mRoundCornerRadius = roundCornerRadius;
	}
	
	@Override
	public Drawable run(ThreadPool.JobContext jc) {
		if (mUrl == null || mUrl.length() <= 0) {
			return null;
		}
		
		try {
			if (mType == MeasuredAsyncDrawable.DRAWABLE_TYPE_ICON) {
				Bitmap bitmap = getBitmapFromCache();
				if (bitmap != null) {
					//Utils.log("getBitmapFromCache: match! %d, %d, %s", cache.getWidth(), cache.getWidth(), mUrl);
					return new BitmapDrawable(mContext.getResources(), bitmap);
				}
			}
			
			if (!prepareInputFile(jc)) {
				return null;
			}
			
			Bitmap bitmap = BitmapUtils.decodeBitmap(jc, mFileDescriptor.getFileDescriptor(),
					mWidth, mHeight, mFitMode, mType, mRoundCornerRadius);
				
			if (jc.isCancelled() || bitmap == null) {
	            return null;
	        }
			
			BitmapDrawable drawable = new BitmapDrawable(mContext.getResources(), bitmap);
			
			if (mType == MeasuredAsyncDrawable.DRAWABLE_TYPE_ICON) {
				putBitmapToCache(bitmap);
			}
			return drawable;
		} finally {
			closeFd();
		}
	}
	
	private Bitmap getBitmapFromCache() {
		synchronized (mIconLruCache) {
			return mIconLruCache.get(mUrl);
		}
	}
	
	private void putBitmapToCache(Bitmap bitmap) {
		synchronized (mIconLruCache) {
			Bitmap b = mIconLruCache.get(mUrl);
			if (b == null) {
				mIconLruCache.put(mUrl, bitmap);
			}
		}
	}
	
	public static void removeBitmapFromCache(String url) {
		synchronized (mIconLruCache) {
			if (mIconLruCache.get(url) != null) {
				mIconLruCache.remove(url);
			}
		}
	}
	
	private void openFileOrDownloadTempFile(ThreadPool.JobContext jc) {
        int state = openOrDownloadInner(jc);
        synchronized (this) {
            mState = state;
            if (mState != STATE_DOWNLOADED) {
                if (mFileDescriptor != null) {
                    Utils.closeSilently(mFileDescriptor);
                    mFileDescriptor = null;
                }
            }
            notifyAll();
        }
    }

    private int openOrDownloadInner(ThreadPool.JobContext jc) {
		//not implement
		return STATE_ERROR;
    }
	
	private boolean prepareInputFile(ThreadPool.JobContext jc) {
        jc.setCancelListener(new ThreadPool.CancelListener() {
            public void onCancel() {
                synchronized (this) {
                    notifyAll();
                }
            }
        });

        while (true) {
            synchronized (this) {
                if (jc.isCancelled()) return false;
                if (mState == STATE_INIT) {
                    mState = STATE_DOWNLOADING;
                    // Then leave the synchronized block and continue.
                } else if (mState == STATE_ERROR) {
                    return false;
                } else if (mState == STATE_DOWNLOADED) {
                    return true;
                } else /* if (mState == STATE_DOWNLOADING) */ {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                        // ignored.
                    }
                    continue;
                }
            }
            // This is only reached for STATE_INIT->STATE_DOWNLOADING
            openFileOrDownloadTempFile(jc);
        }
    }
	
	private void closeFd() {
        if (mFileDescriptor != null && mFileDescriptor instanceof Closeable) {
            Utils.closeSilently(mFileDescriptor);
        }
	}
	
	@Override
    protected void finalize() throws Throwable {
        try {
        	closeFd();
        } finally {
            super.finalize();
        }
    }
}
